package CourseDesign;

import javafx.util.Pair;

import javax.swing.*;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadersWritersProblem {
    static int readers = 0;
    static int writers = 0;
    static boolean writing = false;
    static ReentrantLock mutex = new ReentrantLock();
    static ReentrantLock writeLock = new ReentrantLock();
    static Semaphore write = new Semaphore(1);
    static Random random = new Random();
    static void reader() {
        try {
            mutex.lock();
            readers++;
            if (readers == 1) {
                write.acquire();
            }
            mutex.unlock();

            System.out.println(Thread.currentThread().getName()+" 正在读书，当前读者共有 " + readers);
            Thread.sleep(random.nextInt(200)); // Simulate reading time

            mutex.lock();
            readers--;
            System.out.println(Thread.currentThread().getName()+" 读书完成，当前读者共有 " + readers);
            if (readers == 0) {
                write.release();
            }
            mutex.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static void writer() throws InterruptedException {
        write.acquire();
        System.out.println(Thread.currentThread().getName()+"正在写入");
        Thread.sleep(random.nextInt(10));
        System.out.println(Thread.currentThread().getName()+"写入完成");
        write.release();
    }

    static void readerSecond() {
        try {
            writeLock.lock();
            mutex.lock();
            readers++;
            if (readers == 1) {
                write.acquire();
            }
            mutex.unlock();
            writeLock.unlock();
            System.out.println(Thread.currentThread().getName()+" 正在读书，当前读者共有 " + readers);
            Thread.sleep(random.nextInt(200)); // Simulate reading time

            mutex.lock();
            readers--;
            System.out.println(Thread.currentThread().getName()+" 读书完成，当前读者共有 " + readers);
            if (readers == 0) {
                write.release();
            }
            mutex.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static void writerFirst() throws InterruptedException {
        writeLock.lock();
        write.acquire();
        System.out.println(Thread.currentThread().getName()+"正在写入");
        Thread.sleep(random.nextInt(10));
        System.out.println(Thread.currentThread().getName()+"写入完成");
        write.release();
        writeLock.unlock();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("请输入想要模拟的读者-写者问题");
            System.out.println("1. 读读同时");
            System.out.println("2. 读写互斥（读者优先）");
            System.out.println("3. 写写互斥");
            System.out.println("4. 读写互斥（写者优先）");
            int select = scanner.nextInt();
            switch (select) {
                case 1:{
                    ReadRead();
                    break;
                }
                case 2:{
                    ReadWrite();
                    break;
                }
                case 3:{
                    WriteWrite();
                    break;
                }
                case 4:{
                    ReadWriteWriterFirst();
                    break;
                }
                default:
                    System.out.println("输入有误");
            }
        }
    }

    public static void ReadRead(){
        Thread[] readers = new Thread[5]; // 5 readers

        System.out.println("演示读读同时：:");
        for (int i = 0; i < 5; i++) {
            readers[i] = new Thread(ReadersWritersProblem::reader);
            readers[i].start();
        }
        waitForThreads(readers);
    }

    public static void WriteWrite(){
        Thread[] writers = new Thread[3]; // 3 writers
        System.out.println("展示写写互斥:");
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        for (int i = 0; i < 3; i++) {
            writers[i] = new Thread(()->{
                try {
                    cyclicBarrier.await();
                    writer();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            );

            writers[i].start();
        }
        waitForThreads(writers);
    }

    public static void ReadWriteWriterFirst(){
        System.out.println("展示读写互斥（写者优先）");
        Thread[] writers = new Thread[3];
        Thread[] readers = new Thread[3];
        for (int i = 0; i < 3; i++) {

            readers[i]= new Thread(()->{
                try {
                    System.out.println("当前读者为"+Thread.currentThread().getName());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                readerSecond();
            }
            );

            try {
                Thread.sleep(random.nextInt(220));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            writers[i] = new Thread(()->{
                try {
                    System.out.println("写者 "+Thread.currentThread().getName()+" 已到");
                    writerFirst();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            );
            readers[i].start();
            writers[i].start();
        }
        waitForThreads(readers);
        waitForThreads(writers);
    }

    public static void ReadWrite(){
        System.out.println("展示读写互斥（读者优先）");
        Thread[] writers = new Thread[3];
        Thread[] readers = new Thread[3];
        for (int i = 0; i < 3; i++) {

            readers[i]= new Thread(()->{
                try {
                    System.out.println("当前读者为"+Thread.currentThread().getName());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                reader();
            }
            );

            try {
                Thread.sleep(random.nextInt(220));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            writers[i] = new Thread(()->{
                try {
                    System.out.println("写者 "+Thread.currentThread().getName()+" 已到");
                    writer();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            );
            readers[i].start();
            writers[i].start();

        }
        waitForThreads(readers);
        waitForThreads(writers);
    }
    private static void waitForThreads(Thread[] threads) {
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}